﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TFDP.Common.Configuration;
using System.Xml.Serialization;
using System.ComponentModel;
using System.Runtime.Remoting;

namespace TFDP.SimpleProcessor
{
    [XmlRoot(ElementName = "TemplateMappings", IsNullable = true, Namespace = "http://tfdp.com/2010/ProjectConfiguration")]
    [Editor(typeof(TemplateMappingsEditor), typeof(System.Drawing.Design.UITypeEditor))]
    [XmlInclude(typeof(TemplateMapping))]
    public sealed class TemplateMappings : List<TemplateMapping>, IXmlSerializable, IEquatable<TemplateMappings>, ICloneable
    {
        public const string Namespace = "http://tfdp.com/2010/TemplateMapping";

        public TemplateMappings() : base()
        {
        }

        #region IXmlSerializable Members

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(System.Xml.XmlReader reader)
        {
            while (reader.ReadToFollowing("Mapping", Namespace))
            {
                if (reader.HasAttributes)
                {
                    TemplateMapping mapping = new TemplateMapping();

                    mapping.Type = reader.GetAttribute("Type");
                    mapping.Template = reader.GetAttribute("Template");
                    mapping.Project = reader.GetAttribute("Project");
                    mapping.ObjectNameTemplate = reader.GetAttribute("ObjectNameTemplate");
                    mapping.FileNameTemplate = reader.GetAttribute("FileNameTemplate");

                    string orderString = reader.GetAttribute("Order");
                    int order = 0;
                    Int32.TryParse(orderString, out order);
                    mapping.Order = order;

                    if (reader.ReadToDescendant("Properties", Namespace))
                    {
                        while (reader.ReadToDescendant("Property", Namespace) || reader.ReadToNextSibling("Property", Namespace))
                        {
                            string key = reader.GetAttribute("Key");
                            string value = reader.GetAttribute("Value");

                            mapping.Properties.Add(new MappingProperty() { Key = key, Value = value });
                        }
                    }

                    this.Add(mapping);
                }
            }
        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            writer.WriteStartElement("Mappings", Namespace);

            foreach (var mapping in this)
            {
                writer.WriteStartElement("Mapping", Namespace);

                writer.WriteAttributeString("Type", mapping.Type);
                writer.WriteAttributeString("Template", mapping.Template);
                writer.WriteAttributeString("Project", mapping.Project);
                writer.WriteAttributeString("ObjectNameTemplate", mapping.ObjectNameTemplate);
                writer.WriteAttributeString("FileNameTemplate", mapping.FileNameTemplate);
                writer.WriteAttributeString("Order", mapping.Order.ToString());

                if (mapping.Properties.Count > 0)
                {
                    writer.WriteStartElement("Properties", Namespace);

                    foreach (var kv in mapping.Properties)
                    {
                        writer.WriteStartElement("Property", Namespace);
                        
                        writer.WriteAttributeString("Key", kv.Key);
                        writer.WriteAttributeString("Value", kv.Value);
                        
                        writer.WriteEndElement();
                    }

                    writer.WriteEndElement();
                }
                writer.WriteEndElement();
            }

            writer.WriteEndElement();
        }

        #endregion

        #region IEquatable<TemplateMappings> Members

        public bool Equals(TemplateMappings other)
        {
            if (other == null)
            {
                return false;
            }
            if (this.Count != other.Count)
            {
                return false;
            }
            else
            {
                foreach (TemplateMapping tm in this)
                {
                    if (!other.Any(otm => otm == tm))
                    {
                        return false;
                    }
                }
                foreach (TemplateMapping tm in other)
                {
                    if (!this.Any(otm => otm == tm))
                    {
                        return false;
                    }
                }
            }

            return true;
        }

        public override bool Equals(object other)
        {
            if (other == null)
            {
                return false;
            }

            if (this.GetType() != other.GetType())
            {
                return false;
            }

            // safe because of the GetType check
            TemplateMappings mappings = (TemplateMappings)other;

            return this.Equals(mappings);
        }

        #endregion

        public static bool operator ==(TemplateMappings left, TemplateMappings right)
        {
            if (Object.Equals(left, null) && Object.Equals(right, null))
            {
                return true;
            }
            if (Object.Equals(left, null) && !Object.Equals(right, null))
            {
                return false;
            }
            if (!Object.Equals(left, null) && Object.Equals(right, null))
            {
                return false;
            }
            else
            {
                return left.Equals(right);
            }
        }

        public static bool operator !=(TemplateMappings left, TemplateMappings right)
        {
            return !(left == right);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #region ICloneable Members

        public object Clone()
        {
            TemplateMappings clone = new TemplateMappings();
            
            foreach (TemplateMapping tm in this)
            {
                clone.Add((TemplateMapping)tm.Clone());
            }

            return clone;
        }

        #endregion
    }
}
